﻿using System;
using System.Collections.Generic;
using System.Runtime.Serialization;

namespace IntoNails.Models
{
    [Serializable]
    public class Category : AbstractModel<Guid>, ISerializable
    {
        #region Fields

        private Category _parent;
        private IList<Category> _subCategoryList;

        #endregion

        #region Constructors

        protected Category()
        {
        }

        public Category(SerializationInfo info, StreamingContext context)
        {
            this.UniqueCode = (Guid) info.GetValue("UniqueCode", typeof (Guid));
            this.DisplayName = info.GetString("DisplayName");
            this.Parent = (Category) info.GetValue("Parent", typeof (Category));
            this.SubCategoryList = (IList<Category>)info.GetValue("SubCategoryList", typeof(IList<Category>));
            this.CreatedDate = info.GetDateTime("CreatedDate");
            this.UpdatedDate = info.GetDateTime("UpdatedDate");
            this.IsValid = info.GetBoolean("IsValid");
        }

        #endregion

        #region Properties

        public static Category RootCategory
        {
            get
            {
                return new Category
                           {
                               UniqueCode = Guid.Empty,
                               DisplayName = "Services",
                               SubCategoryList = new List<Category>(),
                               IsValid = true
                           };
            }
        }

        public Category Parent
        {
            get { return this._parent; }
            set
            {
                this._parent = value;
                base.RaisePropertyChanged("Parent");
            }
        }

        public IList<Category> SubCategoryList
        {
            get { return this._subCategoryList; }
            set
            {
                this._subCategoryList = value;
                base.RaisePropertyChanged("SubCategoryListget");
            }
        }

        #endregion

        public static Category CreateNewCategory()
        {
            return new Category
                       {
                           UniqueCode = Guid.NewGuid(),
                           SubCategoryList = new List<Category>(),
                           CreatedDate = DateTime.Now,
                           UpdatedDate = DateTime.Now,
                           IsValid = true
                       };
        }

        public static Category CreateCategory(string categoryName)
        {
            return new Category
                       {
                           UniqueCode = Guid.NewGuid(),
                           DisplayName = categoryName,
                           SubCategoryList = new List<Category>(),
                           CreatedDate = DateTime.Now,
                           UpdatedDate = DateTime.Now,
                           IsValid = true
                       };
        }

        public static Category CreateCategory(string categoryName, Category parent)
        {
            return new Category
                       {
                           UniqueCode = Guid.NewGuid(),
                           DisplayName = categoryName,
                           Parent = parent,
                           SubCategoryList = new List<Category>(),
                           CreatedDate = DateTime.Now,
                           UpdatedDate = DateTime.Now,
                           IsValid = true
                       };
        }

        #region Implementation of ISerializable

        public void GetObjectData(SerializationInfo info, StreamingContext context)
        {
            info.AddValue("UniqueCode", this.UniqueCode);
            info.AddValue("DisplayName", this.DisplayName);
            info.AddValue("Parent", this.Parent);
            info.AddValue("SubCategoryList", this.SubCategoryList);
            info.AddValue("CreatedDate", this.CreatedDate);
            info.AddValue("UpdatedDate", this.UpdatedDate);
            info.AddValue("IsValid", this.IsValid);
        }

        #endregion

        #region Object Overriden

        public override string ToString()
        {
            return string.Format("ID: {0} | Name: {1}", this.UniqueCode, this.DisplayName);
        }

        public override int GetHashCode()
        {
            int hashCode = 0;

            unchecked
            {
                hashCode += this.UniqueCode.GetHashCode();
                hashCode += this.DisplayName.GetHashCode();
                hashCode += this.Parent == null ? 0 : this.Parent.GetHashCode();
                hashCode += this.SubCategoryList.GetHashCode();
                hashCode += this.CreatedDate.GetHashCode();
                hashCode += this.UpdatedDate.GetHashCode();
                hashCode += this.IsValid.GetHashCode();
            }

            return hashCode;
        }

        public override bool Equals(object obj)
        {
            Category other = obj as Category;
            if(other == null)
            {
                return false;
            }

            return this.UniqueCode == other.UniqueCode;
        }

        #endregion
    }
}
